package com.yuandian.business.monitor.documentExport;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuandian.api.business_monitor.po.AdvancedQuery;
import com.yuandian.api.business_monitor.po.DetailedListParams;
import com.yuandian.api.business_monitor.po.SearchParams;
import com.yuandian.api.business_monitor.vo.BusinessDetailedListVO;
import com.yuandian.api.management.entity.ConfDocumentExportInfo;
import com.yuandian.api.management.entity.ConfReturnCode;
import com.yuandian.api.management.feign.RemoteAlarmIndicatorsService;
import com.yuandian.api.management.feign.RemoteReturnCodeService;
import com.yuandian.bpm.common.core.constant.SecurityConstants;
import com.yuandian.business.monitor.mapper.BusinessDetailMapper;
import com.yuandian.business.monitor.service.impl.ExclusiveIndicator;
import com.yuandian.constant.Constants;
import com.yuandian.enums.BaseTableName;
import com.yuandian.utils.ListUtils;
import com.yuandian.utils.StringUtils;
import com.yuandian.utils.YDateUtil;
import com.yuandian.utils.poi.ExcelTitleUtils;
import com.yuandian.utils.poi.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 业务详单下载
 */
@Slf4j
@Service("businessDetailExcelHandler")
public class BusinessDetailExcelHandler implements DocumentExportHandler{

	@Autowired
	private RemoteAlarmIndicatorsService remoteAlarmIndicatorsService;
	@Autowired
	private RemoteReturnCodeService remoteReturnCodeService;

	@Autowired
	private BusinessDetailMapper businessDetailMapper;

	@Autowired
	private ExclusiveIndicator exclusiveIndicator;
	private String[] completionState = new String[]{"不完整", "完整"};
	private String[] dealState = new String[]{"失败", "成功"};

	/**
	 * 下载文件的处理逻辑
	 *
	 * @param confDocumentExportInfo
	 */
	@Override
	public void handle(ConfDocumentExportInfo confDocumentExportInfo) {
		//获取系统现在的时间作为开始时间(时间戳)
		long startTime = System.currentTimeMillis();
		exportExcel(confDocumentExportInfo);
		log.info("业务详单导出成功,耗时: {}ms", (System.currentTimeMillis() - startTime));
	}
	// 异步下载会调用此方法
	public void exportExcel(ConfDocumentExportInfo documentExportApplicationForm) {
		DetailedListParams params = null;
		params = JSONUtil.toBean(documentExportApplicationForm.getDocExportParameterJson(), DetailedListParams.class);
		if (StringUtils.isEmpty(params.getOrderByColumn())) {
			params.setIsAsc("desc");
			params.setOrderByColumn("end_time_usec");
		} else {
			params.setOrderByColumn(StringUtils.toUnderlineName(params.getOrderByColumn()));
		}
		List<AdvancedQuery> advancedQuery = params.getAdvancedQuery();
		//将列名转换成下划线命名
		if(advancedQuery != null &&advancedQuery.size() >0){
			advancedQuery.forEach(e -> e.setColumn(StringUtils.toUnderlineName(e.getColumn())));
			params.setAdvancedQuery(advancedQuery);
		}

		// 设置Excel 信息
		String title = "业务详单列表";
		List<String> titleParams = new ArrayList<>();
		titleParams.add(title);
		titleParams.add(params.getSystemName());
		String formTitleName = ExcelTitleUtils.formTitleName(titleParams, params.getStartTime(), params.getEndTime());
		//需要展示的字段
		List<String> displayFields = new ArrayList<>();
		displayFields.add("序号");
		displayFields.addAll(params.getDisplayFields());
		List<List<String>> headList = new ArrayList<>();
		if (params.getAlarmTypeId() != null) {
			titleParams.add(remoteAlarmIndicatorsService.queryById(params.getAlarmTypeId()).getData().getName());
		}
		displayFields.forEach(s -> {
			List<String> childHeadList = new ArrayList<>();
			childHeadList.add(formTitleName);
			childHeadList.add(s);
			headList.add(childHeadList);
		});

		ExcelWriter excelWriter = null;
		OutputStream outputStream = null;
		try {
			outputStream = new FileOutputStream(documentExportApplicationForm.getExportFileName());
			excelWriter = EasyExcel.write(outputStream).build();
			long total = 0;
			// 初始化序号
			int index = 1, sheetIndex = 0, writeNum = 0;
			int pageNum = 1, pageSize = 5000;
			// 获取 自定义返回码注释 回填到前端
			Map<String, String> codeMap = getCodeExplain();

			List<List<Object>> excelList = new ArrayList<>();
			LinkedHashMap<String, Object> customMap = exclusiveIndicator.getCustomMapInner();
			IPage page = new Page(pageNum, pageSize);
			//创建第一个sheet页
			WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex, title + (++sheetIndex))
					.registerWriteHandler(ExcelUtil.defaultStyle)
					.head(headList)
					.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
					.registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 30, (short) 20))
					.build();
			while (true) {
				log.info("开始查询第" + pageNum + "页数据");
				// 判断查询 定性详单表(dws_business_detail) 还是 未定性的详单表(dws_business_detail_unsure)
				params.setTableName(params.getIsUnsure() == 0 ? BaseTableName.BUSINESS_DETAIL.getName() : BaseTableName.BUSINESS_DETAIL_UNSURE.getName());
				List<BusinessDetailedListVO> list = businessDetailMapper.queryList(page, params);
				total = page.getTotal();
				page.setCurrent(++pageNum);
				for (BusinessDetailedListVO businessDetailedListVO : list) {
					// 把数据封装成横向 List
					List<Object> rowListByHit = getRowListByHit(businessDetailedListVO, codeMap, params.getDisplayMappingFields(), index, customMap);
					index++;
					excelList.add(rowListByHit);
				}
				//如果行数超过60000另起一页
				if (index >= Constants.SHEET_MAX_ROW * sheetIndex) {
					int tempIndex = Constants.SHEET_MAX_ROW * sheetIndex - writeNum;
					List<List<Object>> preLists = excelList.subList(0, tempIndex);
					excelWriter.write(preLists, writeSheet);
					// 每次都要创建writeSheet 这里必须指定sheetNo 而且sheetName必须不一样
					writeSheet = EasyExcel.writerSheet(sheetIndex, title + (++sheetIndex))
							.registerWriteHandler(ExcelUtil.defaultStyle)
							.head(headList)
							.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
							.registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 30, (short) 20))
							.build();
					List<List<Object>> sufLists = excelList.subList(tempIndex, excelList.size() - 1);
					excelWriter.write(sufLists, writeSheet);
				}
				excelWriter.write(excelList, writeSheet);
				writeNum = index;
				if (pageNum > page.getPages() || page.getTotal() == 0) {
					log.info("共导出数据：{}条，当前页数：{}", index, pageNum);
					break;
				}
				//清空数据
				excelList.clear();
			}
		} catch (Exception e) {
			log.error("下载详单查询列表出错！");
			throw new RuntimeException("下载详单查询列表出错! " + e);
		} finally {
			if (excelWriter != null) {
				try {
					outputStream.flush();
					excelWriter.finish();
					outputStream.close();
				} catch (Exception e) {
					log.error("IO流关闭异常： " + e.getMessage());
					throw new RuntimeException("IO流关闭异常： " + e.getMessage());
				}
			}
		}
	}

	public Map<String, String> getCodeExplain() {

		Map<String, String> resMap = new HashMap<>();
		SearchParams params = new SearchParams();
		// 4:自定返回码类型  3: 数据库返回码 2：中间件返回码  1：web 返回码
		ConfReturnCode confReturnCode = new ConfReturnCode();
		confReturnCode.setTypeId(4);
		List<ConfReturnCode> list = remoteReturnCodeService.getCodeDetail(confReturnCode, SecurityConstants.FROM_IN).getData();
		if (list != null && list.size() > 0) {
			resMap = list.stream().collect(Collectors.toMap(ConfReturnCode::getNameAndValue, ConfReturnCode::getExplain, (key1, key2) -> key2));
		}
		return resMap;
	}


	/**
	 * 组装数据成 List(把单行数据组成横向的List)
	 *
	 * @param businessDetailedListVO
	 * @param codeMap
	 * @param displayMappingFields
	 * @param excelId
	 * @return
	 */
	private List<Object> getRowListByHit(BusinessDetailedListVO businessDetailedListVO,
										 Map<String, String> codeMap,
										 List<String> displayMappingFields,
										 int excelId,
										 LinkedHashMap<String, Object> customMap) {

		Map<String, Object> map = BeanUtil.beanToMap(businessDetailedListVO);
		// 从后台配置获取需要从专属指标提取的字段并从专属指标中提取该字段对应的值
		LinkedHashMap<String, Object> customIndicatorMap = new LinkedHashMap<>();
		ExclusiveIndicator.getValueFromSpecifyParameters(customMap, map.get("exclusiveIndicator") + "");
		if (customIndicatorMap == null) {
			customIndicatorMap = new LinkedHashMap<>();
		}

		// 保存行数据的横向List
		List<Object> rowList = new ArrayList<>();
		rowList.add(excelId);

		String explain = "";
		if (ListUtils.isNotNull(displayMappingFields)) {
			for (String field : displayMappingFields) {
				Object value = map.get(field);
				// 对字段进行特殊处理
				if ("completionState".equals(field)) {
					value = completionState[Convert.toInt(map.get("completionState"))];
				} else if ("dealState".equals(field)) {
					value = dealState[Convert.toInt(map.get("dealState"))];
				} else if ("dealTime".equals(field)) {
					value = YDateUtil.getMinSecond(Double.parseDouble(map.get("dealTime").toString()) / 1000);
				} else if ("clientFreeTime".equals(field)) {
					value = YDateUtil.getMinSecond(Double.parseDouble(map.get("clientFreeTime").toString()) / 1000);
				} else if ("customResCode".equals(field)) {
					explain = codeMap.get(map.get("systemName") + "@" + map.get("customResCode"));
					explain = StringUtils.isEmpty(explain) ? "" : (" (" + explain + ")");
					value = map.get("customResCode") + explain;
				} else if (!"exclusiveIndicator".equals(field) && customIndicatorMap.get(field) != null) {
					value = customIndicatorMap.get(field);
				}

				rowList.add(value);
			}
		}
		return rowList;
	}




}
